/*
gcc -o my_httpd my_httpd.c -L/usr/local/lib/ -levent -I/usr/local/include/ -lz -lbz2 -lrt -lpthread -lm -lc -O2
*/

//#include <sys/types.h>
//#include <sys/time.h>
//#include <sys/queue.h>
//#include <sys/types.h>
//#include <sys/socket.h>
//#include <sys/stat.h>
//#include <sys/mman.h>
//#include <sys/ioctl.h>
//#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
//#include <stdint.h>
#include <string.h>
//#include <strings.h>
//#include <getopt.h>
#include <unistd.h>
//#include <netinet/in.h>
//#include <net/if.h>
//#include <netdb.h>
//#include <arpa/inet.h>
//#include <fcntl.h>
#include <time.h>
#include <errno.h>
//#include <assert.h>
//#include <signal.h>
//#include <stdbool.h>
//#include <err.h>

// 引入 libevent 头文件
#include <event.h>
#include <evhttp.h>

#ifndef u_int
#define u_int unsigned int
#endif

#ifndef u_long
#define u_long unsigned long
#endif

// 引入 BDB 头文件
#include <db.h>

#define DATABASE  "zc_cache.db"

DB *dbp;
DBT key, value;
char user_key[128];
char user_value[128];


// 请求处理模块
void http_handler(struct evhttp_request *req, void *arg)
{
	int ret;

    struct evbuffer *buf;
    buf = evbuffer_new();

    // 分析URL参数
    char *decode_uri = evhttp_request_uri(req);
    struct evkeyvalq http_query;
    evhttp_parse_query(decode_uri, &http_query);
    free(decode_uri);

    // 从http头中获取参数，如果是GET传输，这里就可以取得action的值
    const char *request_opt = evhttp_find_header(&http_query, "opt");
    const char *request_key = evhttp_find_header(&http_query, "key");
    const char *request_value = evhttp_find_header(&http_query, "value");

	memset(&key, 0, sizeof(key));
    memset(&value, 0, sizeof(value));
	memset(user_key, 0, sizeof(user_key));
    memset(user_value, 0, sizeof(user_value));

	if(strcmp(request_opt, "put") == 0) {
		strncpy(user_key, request_key, sizeof(user_key)-1);
		strncpy(user_value, request_value, sizeof(user_value)-1);

	    key.data = user_key;
	    key.size = strlen(user_key);
	    value.data = user_value;
	    value.size = strlen(user_value);

	    if ((ret = dbp->put(dbp, NULL, &key, &value, 0)) == 0) {
			printf("db: %s: key stored.\n", (char *)key.data);
			evbuffer_add_printf(buf, "%s ok!", request_opt);
	    } else {
			dbp->err(dbp, ret, "DB->put");
			evbuffer_add_printf(buf, "%s error!", request_opt);
		}
	} else if(strcmp(request_opt, "get") == 0) {
		strncpy(user_key, request_key, sizeof(user_key)-1);

		key.data = user_key;
	    key.size = strlen(user_key);
		value.data = user_value;
	    value.ulen = sizeof(user_value)-1;
	    value.flags = DB_DBT_USERMEM;

	    if ((ret = dbp->get(dbp, NULL, &key, &value, 0)) == 0) {
			printf("db: %s: key retrieved: data was %s.\n", (char *)key.data, user_value);
			evbuffer_add_printf(buf, "%s ok!\r\n%s", request_opt, user_value);
	    } else {
			dbp->err(dbp, ret, "DB->get");
			evbuffer_add_printf(buf, "%s error!", request_opt);
		}
	} else if(strcmp(request_opt, "remove") == 0) {
		strncpy(user_key, request_key, sizeof(user_key)-1);

		key.data = user_key;
	    key.size = strlen(user_key);

		if((ret = dbp->del(dbp, NULL, &key, 0)) == 0) {
			printf("db: %s: key was deleted.\n", (char *)key.data);
			evbuffer_add_printf(buf, "%s ok!", request_opt);
	    } else {
			dbp->err(dbp, ret, "DB->del");
			evbuffer_add_printf(buf, "%s error!", request_opt);
		}
	} else {
		evbuffer_add_printf(buf, "%s error!", request_opt);

		return;
	}

    // 返回给浏览器的信息
    evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=UTF-8");
    evhttp_add_header(req->output_headers, "Server", "other_httpd");
    evhttp_add_header(req->output_headers, "Connection", "keep-alive");
    //evhttp_add_header(req->output_headers, "Connection", "close");

    // 输出内容到浏览器
    evhttp_send_reply(req, HTTP_OK, "OK", buf);

    // 内存释放
    evhttp_clear_headers(&http_query);
    evbuffer_free(buf);

    free(decode_uri);
}

int main(int argc, char **argv)
{
    char *host_ip = "0.0.0.0";
    int host_port = 8080;
    int timeout = 3;


    int ret;
    u_int32_t env_flags;

    env_flags = DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_TXN | DB_THREAD | DB_AUTO_COMMIT;
	if ((ret = db_create(&dbp, 0, 0)) != 0)
    {
          fprintf(stderr, "db_create: %s\n", db_strerror(ret));
          exit (1);
    }

    if ((ret = dbp->open(dbp, NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0)
    {
          dbp->err(dbp, ret, "%s", DATABASE);
          exit (1);
    }

////////////////////////////////////////

    struct evhttp *httpd;

    event_init();

    // 绑定本机ip和端口，在访问时一定要把8080端口开放出来
    httpd = evhttp_start(host_ip, host_port);

    if (httpd == NULL) {
        fprintf(stderr, "Error: Unable to listen on %s:%d\n\n", host_ip, host_port);
        exit(1);
    }

    // 设置请求超时时间
    evhttp_set_timeout(httpd, timeout);

    // 设置请求的处理函数
    evhttp_set_gencb(httpd, http_handler, NULL);

    event_dispatch();

    evhttp_free(httpd);

    return 0;
}

